import { findIndex } from "./search";
import {
	FRAME_INTERVAL,
	PREVIEW_FRAME_WIDTH,
	TIMELINE_OFFSET_X,
} from "../constants/constants";
import { ITimelineScaleState } from "@designcombo/types";
import { TIMELINE_ZOOM_LEVELS } from "../constants/scale";

export function getPreviousZoomLevel(
	currentZoom: ITimelineScaleState,
): ITimelineScaleState {
	const previousZoom = getPreviousZoom(currentZoom);

	return previousZoom || TIMELINE_ZOOM_LEVELS[0];
}

export function getZoomByIndex(index: number) {
	return TIMELINE_ZOOM_LEVELS[index];
}
export function getNextZoomLevel(
	currentZoom: ITimelineScaleState,
): ITimelineScaleState {
	const nextZoom = getNextZoom(currentZoom);

	return nextZoom || TIMELINE_ZOOM_LEVELS[TIMELINE_ZOOM_LEVELS.length - 1];
}

export const getPreviousZoom = (
	currentZoom: ITimelineScaleState,
): ITimelineScaleState | null => {
	// Filter zoom levels that are smaller than the current zoom
	const smallerZoomLevels = TIMELINE_ZOOM_LEVELS.filter(
		(level) => level.zoom < currentZoom.zoom,
	);

	// If there are no smaller zoom levels, return null (no previous zoom)
	if (smallerZoomLevels.length === 0) {
		return null;
	}

	// Get the zoom level with the largest zoom value that's still smaller than the current zoom
	const previousZoom = smallerZoomLevels.reduce((prev, curr) =>
		curr.zoom > prev.zoom ? curr : prev,
	);

	return previousZoom;
};

export const getNextZoom = (
	currentZoom: ITimelineScaleState,
): ITimelineScaleState | null => {
	// Filter zoom levels that are larger than the current zoom
	const largerZoomLevels = TIMELINE_ZOOM_LEVELS.filter(
		(level) => level.zoom > currentZoom.zoom,
	);

	// If there are no larger zoom levels, return null (no next zoom)
	if (largerZoomLevels.length === 0) {
		return null;
	}

	// Get the zoom level with the smallest zoom value that's still larger than the current zoom
	const nextZoom = largerZoomLevels.reduce((prev, curr) =>
		curr.zoom < prev.zoom ? curr : prev,
	);

	return nextZoom;
};

export function getFitZoomLevel(
	totalLengthMs: number,
	zoom = 1,
	scrollOffset = 8, // Default fallback value
): ITimelineScaleState {
	const getVisibleWidth = () => {
		const clampedScrollOffset = Math.max(0, scrollOffset);

		const timelineCanvas = document.getElementById(
			"designcombo-timeline-canvas",
		) as HTMLElement;
		const offsetWidth =
			timelineCanvas?.offsetWidth ?? document.body.offsetWidth;

		// Use 1 to prevent NaN because of dividing by 0.
		return Math.max(1, offsetWidth - clampedScrollOffset);
	};

	const getFullWidth = () => {
		if (typeof totalLengthMs === "number") {
			return timeMsToUnits(totalLengthMs, zoom);
		}

		return calculateTimelineWidth(totalLengthMs, zoom);
	};

	const multiplier = getVisibleWidth() / getFullWidth();
	const targetZoom = zoom * multiplier;

	const fitZoomIndex = findIndex(TIMELINE_ZOOM_LEVELS, (level) => {
		return level.zoom > targetZoom;
	});

	// const clampedIndex = clamp(fitZoomIndex, 0, TIMELINE_ZOOM_LEVELS.length - 1);

	return {
		segments: 5,
		index: fitZoomIndex,
		zoom: targetZoom,
		unit: 1 / targetZoom,
	};
}

export function timeMsToUnits(timeMs: number, zoom = 1): number {
	const zoomedFrameWidth = PREVIEW_FRAME_WIDTH * zoom;
	const frames = timeMs * (60 / 1000);

	return frames * zoomedFrameWidth;
}

export function unitsToTimeMs(units: number, zoom = 1): number {
	const zoomedFrameWidth = PREVIEW_FRAME_WIDTH * zoom;

	const frames = units / zoomedFrameWidth;

	return frames * FRAME_INTERVAL;
}

export function calculateTimelineWidth(
	totalLengthMs: number,
	zoom = 1,
): number {
	return timeMsToUnits(totalLengthMs, zoom);
}
